﻿using Furion;
using Furion.FriendlyException;
using Photo.Core.Dtos.Dto;
using Photo.Core.Dtos.Entity;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Photo.Respository
{
    /// <summary>
    /// 仓储模式
    /// 必须继承至DEntityBase的实体类表才行
    /// 作用：1.业务代码和orm解耦,2.每个方法操作的表必须在构造函数中经过仓储，更好的排查问题所在
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class Repository<TEntity> : SimpleClient<TEntity>, IRepository<TEntity> where TEntity : BaseEntity, new()
    {
        /// <summary>
        /// 用户id
        /// </summary>
        public string UserId { get; set; }
        /// <summary>
        /// 用户名称
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="context"></param>
        public Repository(ISqlSugarClient context = null) : base(context)//默认值等于null不能少
        {
            base.Context = App.GetService<ISqlSugarClient>();

            Context.Ado.CommandTimeOut = 10;//单位秒，超时

            Context.QueryFilter.Add(new SqlFilterItem//单表全局过滤器
            {
                FilterValue = _filterDb =>
                {
                    return new SqlFilterResult()
                    {
                        Sql = " IsDeleted!=1"
                    };
                },
                IsJoinQuery = false
            })
            .Add(new SqlFilterItem//多表全局过滤器
            {
                FilterValue = _filterDb =>
                {
                    return new SqlFilterResult()
                    {
                        Sql = " f.IsDeleted=0"
                    };
                },
                IsJoinQuery = true
            });

            UserId = App.User?.FindFirstValue("UserId");
            UserName = App.User?.FindFirstValue("UserName");
        }

        /// <summary>
        /// 扩展异步添加
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="errorText"></param>
        public virtual async Task InsertAsync(TEntity entity, string errorText = null)
        {
            entity.CreationTime = DateTime.Now;
            entity.CreatorUserId = UserId;
            entity.CreatorUserName = UserName;
            if (!(await Context.Insertable(entity).ExecuteCommandAsync() > 0))
                throw Oops.Oh(errorText ?? "添加至数据库失败");
        }

        /// <summary>
        /// 扩展异步添加
        /// </summary>
        /// <param name="list"></param>
        /// <param name="errorText"></param>
        public virtual async Task InsertAsync(List<TEntity> list, string errorText = null)
        {
            if (list.Count > 0)
            {
                list.ForEach(entity =>
                {
                    entity.CreationTime = DateTime.Now;
                    entity.CreatorUserId = UserId;
                    entity.CreatorUserName = UserName;
                });
                if (await Context.Insertable(list).ExecuteCommandAsync() != list.Count)
                    throw Oops.Oh(errorText ?? "添加至数据库失败");
            }
        }

        /// <summary>
        /// 扩展异步修改
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="errorText"></param>
        public virtual async Task UpdateAsync(TEntity entity, string errorText = null)
        {
            entity.LastModificationTime = DateTime.Now;
            entity.LastModifierUserId = UserId;
            entity.LastModifierUserName = UserName;

            if (!(await Context.Updateable(entity).ExecuteCommandAsync() > 0))
                throw Oops.Oh(errorText ?? "修改至数据库失败");
        }

        /// <summary>
        /// 扩展异步修改
        /// </summary>
        /// <param name="list"></param>
        /// <param name="errorText"></param>
        public virtual async Task UpdateAsync(List<TEntity> list, string errorText = null)
        {
            if (list.Count > 0)
            {
                list.ForEach(entity =>
                {
                    entity.LastModificationTime = DateTime.Now;
                    entity.LastModifierUserId = UserId;
                    entity.LastModifierUserName = UserName;
                });
                if (await Context.Updateable(list).ExecuteCommandAsync() != list.Count)
                    throw Oops.Oh(errorText ?? "修改至数据库失败");
            }
        }

        /// <summary>
        /// 扩展异步修改
        /// </summary>
        /// <param name="columns"></param>
        /// <param name="whereExpression"></param>
        public virtual async Task<int> UpdateAsync(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, bool>> columns)
        {
            return await Context.Updateable<TEntity>()
                .SetColumns(columns)
                .SetColumns(o => o.LastModificationTime == DateTime.Now)
                .SetColumns(o => o.LastModifierUserId == UserId)
                .SetColumns(o => o.LastModifierUserName == UserName)
                .Where(whereExpression)
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 扩展异步删除
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="errorText"></param>
        public virtual async Task DeleteAsync(TEntity entity, string errorText = null)
        {
            entity.IsDeleted = true;
            entity.DeletionTime = DateTime.Now;
            entity.DeleterUserId = UserId;
            entity.DeleterUserName = UserName;

            if (!(await Context.Updateable(entity).ExecuteCommandAsync() > 0))
                throw Oops.Oh(errorText ?? "从数据库删除失败");
        }

        /// <summary>
        /// 扩展异步删除
        /// </summary>
        /// <param name="list"></param>
        /// <param name="errorText"></param>
        public virtual async Task DeleteAsync(List<TEntity> list, string errorText = null)
        {
            list.ForEach(entity =>
            {
                entity.IsDeleted = true;
                entity.DeletionTime = DateTime.Now;
                entity.DeleterUserId = UserId;
                entity.DeleterUserName = UserName;
            });
            if (await Context.Updateable(list).ExecuteCommandAsync() != list.Count)
                throw Oops.Oh(errorText ?? "从数据库删除失败");
        }

        /// <summary>
        /// 扩展异步删除-按条件
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public new async Task<int> DeleteAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Updateable<TEntity>()
                .SetColumns(o => o.DeletionTime == DateTime.Now)
                .SetColumns(o => o.DeleterUserId == UserId)
                .SetColumns(o => o.DeleterUserName == UserName)
                .SetColumns(o => o.IsDeleted == true)
                .Where(whereExpression)
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 扩展根据主键查询实体
        /// </summary>
        /// <param name="primaryKey"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> GetAsync(string primaryKey)
        {
            return await Context.Queryable<TEntity>().InSingleAsync(primaryKey);
        }

        /// <summary>
        /// 扩展根据主键查询实体
        /// </summary>
        /// <param name="primaryKey"></param>
        /// <returns></returns>
        public virtual async Task<TPurposeEntity> GetAsync<TPurposeEntity>(string primaryKey)
        {
            return await Context.Queryable<TEntity>().Where(o => o.Id == primaryKey).Select<TPurposeEntity>().SingleAsync();
        }

        /// <summary>
        /// 扩展根据主键查询实体
        /// </summary>
        /// <param name="primaryKey"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> GetAsync(string primaryKey, string errorText)
        {
            var entity = await Context.Queryable<TEntity>().InSingleAsync(primaryKey);
            if (entity == null)
                throw Oops.Oh(errorText);
            return entity;
        }

        /// <summary>
        /// 扩展根据主键查询实体
        /// </summary>
        /// <param name="primaryKey"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<TPurposeEntity> GetAsync<TPurposeEntity>(string primaryKey, string errorText)
        {
            var entity = await Context.Queryable<TEntity>().Where(o=>o.Id== primaryKey).Select<TPurposeEntity>().SingleAsync();
            if (entity == null)
                throw Oops.Oh(errorText);
            return entity;
        }

        /// <summary>
        /// 扩展根据条件查询实体
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).FirstAsync();
        }

        /// <summary>
        /// 扩展根据条件查询实体
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual async Task<TPurposeEntity> GetAsync<TPurposeEntity>(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).Select<TPurposeEntity>().FirstAsync();
        }

        /// <summary>
        /// 扩展根据条件查询实体
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> whereExpression, string errorText)
        {
            var entity = await Context.Queryable<TEntity>().Where(whereExpression).FirstAsync();
            if (entity == null)
                throw Oops.Oh(errorText);
            return entity;
        }

        /// <summary>
        /// 扩展根据条件查询实体
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<TPurposeEntity> GetAsync<TPurposeEntity>(Expression<Func<TEntity, bool>> whereExpression, string errorText)
        {
            var entity = await Context.Queryable<TEntity>().Where(whereExpression).Select<TPurposeEntity>().FirstAsync();
            if (entity == null)
                throw Oops.Oh(errorText);
            return entity;
        }

        /// <summary>
        /// 扩展获取列表
        /// </summary>
        /// <returns></returns>
        public override  async Task<List<TEntity>> GetListAsync()
        {
            return await Context.Queryable<TEntity>().ToListAsync();
        }

        /// <summary>
        /// 扩展获取列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TPurposeEntity>> GetListAsync<TPurposeEntity>()
        {
            return await Context.Queryable<TEntity>().Select<TPurposeEntity>().ToListAsync();
        }

        /// <summary>
        /// 扩展根据条件获取列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public override async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).ToListAsync();
        }

        /// <summary>
        /// 扩展根据条件获取列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual async Task<List<TPurposeEntity>> GetListAsync<TPurposeEntity>(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).Select<TPurposeEntity>().ToListAsync();
        }

        /// <summary>
        /// 扩展根据条件获取列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderbyExpression"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderbyExpression, OrderByType type = OrderByType.Asc)
        {
            return await Context.Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderbyExpression, type).ToListAsync();
        }

        /// <summary>
        /// 扩展根据条件获取列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderbyExpression"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public virtual async Task<List<TPurposeEntity>> GetListAsync<TPurposeEntity>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderbyExpression, OrderByType type = OrderByType.Asc)
        {
            return await Context.Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderbyExpression, type).Select<TPurposeEntity>().ToListAsync();
        }

        /// <summary>
        /// 扩展根据主键查询实体指定字段
        /// </summary>
        /// <param name="primaryKey"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<TField> GetFieldAsync<TField>(string primaryKey, Expression<Func<TEntity, TField>> expression)
        {
            return await Context.Queryable<TEntity>().Where(o => o.Id == primaryKey).Select(expression).SingleAsync();
        }

        /// <summary>
        /// 扩展根据主键查询实体指定字段
        /// </summary>
        /// <param name="primaryKey"></param>
        /// <param name="expression"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<TField> GetFieldAsync<TField>(string primaryKey, Expression<Func<TEntity, TField>> expression, string errorText)
        {
            var fieldData = await Context.Queryable<TEntity>().Where(o => o.Id == primaryKey).Select(expression).SingleAsync();
            if (fieldData == null)
                throw Oops.Oh(errorText);
            return fieldData;
        }

        /// <summary>
        /// 扩展根据条件查询实体指定字段
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<TField> GetFieldAsync<TField>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TField>> expression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).Select(expression).FirstAsync();
        }

        /// <summary>
        /// 扩展根据条件查询实体指定字段
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="expression"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<TField> GetFieldAsync<TField>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TField>> expression, string errorText)
        {
            var fieldData = await Context.Queryable<TEntity>().Where(whereExpression).Select(expression).FirstAsync();
            if (fieldData == null)
                throw Oops.Oh(errorText);
            return fieldData;
        }

        /// <summary>
        /// 扩展获取指定字段列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TField>> GetFieldListAsync<TField>(Expression<Func<TEntity, TField>> expression)
        {
            return await Context.Queryable<TEntity>().Select(expression).ToListAsync();
        }

        /// <summary>
        /// 扩展获取指定字段列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TField>> GetFieldListAsync<TField>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TField>> expression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).Select(expression).ToListAsync();
        }

        /// <summary>
        /// 扩展获取指定字段列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TField>> GetFieldListAsync<TField>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TField>> expression, Expression<Func<TEntity, object>> orderbyExpression, OrderByType type = OrderByType.Asc)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).OrderBy(orderbyExpression, type).Select(expression).ToListAsync();
        }

        /// <summary>
        /// 扩展获取指定字段去重列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TField>> GetFieldDistinctListAsync<TField>(Expression<Func<TEntity, TField>> expression)
        {
            return await Context.Queryable<TEntity>().Select(expression).Distinct().ToListAsync();
        }

        /// <summary>
        /// 扩展获取指定字段去重列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TField>> GetFieldDistinctListAsync<TField>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TField>> expression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).Select(expression).Distinct().ToListAsync();
        }

        /// <summary>
        /// 扩展获取指定字段列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TField>> GetFieldDistinctListAsync<TField>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TField>> expression, Expression<Func<TEntity, object>> orderbyExpression, OrderByType type = OrderByType.Asc)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).OrderBy(orderbyExpression, type).Select(expression).Distinct().ToListAsync();
        }

        /// <summary>
        /// 扩展根据条件查询数量
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public override async Task<int> CountAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).CountAsync();
        }

        /// <summary>
        /// 扩展根据条件获取是否存在
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Context.Queryable<TEntity>().Where(whereExpression).AnyAsync();
        }

        /// <summary>
        /// 扩展根据条件获取是否存在
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> whereExpression, string errorText)
        {
            var flag = await Context.Queryable<TEntity>().Where(whereExpression).AnyAsync();
            if (!flag)
                throw Oops.Oh(errorText);
            return flag;
        }

        /// <summary>
        /// 扩展根据条件获取是否不存在
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual async Task<bool> NotAnyAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return !await Context.Queryable<TEntity>().Where(whereExpression).AnyAsync();
        }

        /// <summary>
        /// 扩展根据条件获取是否不存在
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public virtual async Task<bool> NotAnyAsync(Expression<Func<TEntity, bool>> whereExpression, string errorText)
        {
            var flag = !await Context.Queryable<TEntity>().Where(whereExpression).AnyAsync();
            if (!flag)
                throw Oops.Oh(errorText);
            return flag;
        }

        /// <summary>
        /// 扩展获取query
        /// </summary>
        /// <returns></returns>
        public virtual ISugarQueryable<TEntity> Query()
        {
            return Context.Queryable<TEntity>();
        }
    }

}